﻿/****************************************************************************
** file: dmc_b140_m.h
** brief: Galil DMC B140M 的支持代码
** Copyright (C) LiYuan
** Author: LiYuan
** E-Mail: 18069211#qq(.)com
** Version 1.1
** Last modified: 2019.02.11
** Modified By: LiYuan
****************************************************************************/

#ifndef DMC_B140_M_H
#define DMC_B140_M_H
#include <QVector>
#include <QTimer>
#include <QQueue>
#include "motioncontroller.h"

class QIODevice;
class QSerialPort;
class QTcpSocket;

class DMC_B140_M: public MotionController
{
    Q_OBJECT
public:
    explicit DMC_B140_M(QObject *parent = nullptr);
    ~DMC_B140_M() override;
    bool isValid() override; //@
    void init() override;
    bool action1() override;
    bool action2() override;
/// 速度相关
    bool setSpeed(unsigned short axis, int speed) override; //@
    bool setAcceleration(unsigned short axis, int acceleration) override; //@
    bool setDeceleration(unsigned short axis, int deceleration) override; //@
    bool setHomeSpeed(unsigned short axis, int speed) override; //@
/// 运动相关
    bool moveTo(unsigned short axis, int position) override; //@
    bool move(unsigned short axis, int dir = 1) override; //@
    bool moveXYSteps(int stepX, int stepY, int spd) override; //@
    bool moveSteps(unsigned short axis, int steps) override; //@
    bool home(unsigned short axis) override; //@
    bool goHome(unsigned short axis, int speed) override; //@
    bool stopAxis(unsigned short axis) override;  //@
    bool stop() override; //@
    bool abort() override; //@

//// 位置相关
    bool readTheoryPos(unsigned short axis, int32_t &value) override; //@
    bool readTheoryPosAll(int value[]) override; //@
    bool readEncoderPos(unsigned short axis, int32_t &value) override; //@
    bool readEncoderPosAll(int value[4]) override; //@
    bool setStartSpeed(unsigned short axis, int startSpeed) override; //@
    bool setStopSpeed(unsigned short axis, int stopSpeed) override; //@
    bool setTheoryPos(unsigned short axis, int32_t offset) override; //@
    bool setEncoderPos(unsigned short axis, int32_t offset) override; //@

//// 运动状态相关函数
    bool isMoving(unsigned short axis, bool& state) override; //@
    bool isSMoving(bool &state); //@

    /// 前后限位的状态受 CN 命令影响， CN 1 时 true 表示到限位，CN -1 时 false 表示到限位
    bool isReverseLimit(unsigned short axis, bool& state) override; //@
    bool isForwardLimit(unsigned short axis, bool& state) override; //@
    bool isHome(unsigned short axis, bool& state) override; //@
    bool readLimitStatus(unsigned short axis, bool &llimit, bool &rlimit, bool &home) override;  // 返回左右限位和原点状态
    bool readAxisEMStop(bool emstop[]) override;  //B140 支持单轴的急停信号，需要使用 CN,,,1 命令配置。 IN5,6,7,8 对应 ABCD 轴的急停
    bool isEMStop(bool &state) override; //@
//// IO 相关函数
    /**
     * @brief readIOBit 读取 IO 输入数据
     * @param bitNo 0...3
     * @param value
     * @return
     */
    bool readIOBit(int bitNo, bool &value) override;
    bool readIOPort(int port, uint32_t &value) override;

    /**
     * @brief writeIOBit 设置第 bitNo 位
     * @param bitNo  0...3
     * @param value  0 表示复位为0， 非零表示置位
     * @return
     */
    bool writeIOBit(int bitNo, bool value) override;
    bool writeIOPort(int port, uint32_t value) override;

    bool setPWMOut(int channel, double freq, double duty) override;  //B140 不支持
    bool PWMValue(int channel, double &freq, double &duty) override; //B140 不支持

    /**
     * @brief setSoftLlimit 设置正向软限位
     * @param axis
     * @param llimit
     * @return
     */
    bool setSoftLlimit(unsigned short axis, int32_t llimit = -2147483648) override;
    bool setSoftRlimit(unsigned short axis, int32_t rlimit = -2147483648) override;


    // B140 支持网口和 RS232 两种通讯方式。下面是对这两种接口的支持。
    // 通常我们只需要通过一种接口来连接。
    bool connectViaSerialPort(QString commName = "COM1", int baudrate = 9600, char parity = 'N', int dataBits = 8, int stopBits = 1);//@
    bool connectViaEthernet(QString ip, uint16_t port = 23); //@

    void closeEthernet(); //@
    void closeSerialPort(); //@


    bool setEMStop(bool on); //@
    bool setAxisEMStop(bool on); //@

    bool isTCPConnected(); //@

    /// 用于不需要返回值的命令
    bool cmdV(QString cmd, char desiredReturn = ':');

    bool cmdD(QString cmd, double &value);

    /// 用于返回 2 个 Double 值
    bool cmdD2(QString cmd, double value[], char sep = ',');

    /// 用于返回 3 个 Double 值
    bool cmdD3(QString cmd, double value[], char sep = ' ');

    /// 用于返回 4 个 Double 值
    bool cmdD4(QString cmd, double value[4], char sep = ',');

    /// 用于返回一个 int 值的命令
    bool cmdI(QString cmd, int &value);

    /// 用于返回 4 个int 值的命令
    bool cmdI4(QString cmd, int value[4], char sep = ',');

signals:
    void cmdTimeout();
    void connectionLost();
    void connectionSetup();
    void tcpConnectTimeout();

private:

    /**
     * @brief stopCode
     * @param axis
     * @param value
     * @return
     */
    bool stopCode(unsigned short axis,  int32_t &value);
    bool stopCode(int32_t value[4]);
    void updatePosition(); //@
    void updateAxisStatus();
    void updateLimitStatus(); //@
    void updateINPort(); //@

    int m_axis = 4;
    bool m_enableEMStop = false; // 记录是否开启了急停
    bool m_enableAxisEMStop = false;

    /// 以下是通讯相关的变量
    QIODevice * m_io = nullptr;
    QTcpSocket * m_socket = nullptr;  // 对网口的支持，采用 TCP 连接。
    QSerialPort * m_serial = nullptr; // 增加了对 RS232 串口的支持。

    QString m_received; // 调试时使用。用来输出最近收到的命令反馈文本
    QTimer *m_pTimer = nullptr;
    bool m_isTCPPortOK = false;
    bool m_isSerialPortOK = false;

    /// 以下是运动状态相关的变量
    int32_t m_homeSpeed[4]; // 回零速度
    int32_t m_speed[4];//速度绝对值
    int32_t m_encoderPos[4];//光栅尺初始位置
    int32_t m_theoryPos[4];//理论初始位置
    int32_t m_acceleration[4];
    int32_t m_deceleration[4];

    uint8_t m_axisStatus[4];
    uint8_t m_multicoorStatus[4];
    bool m_rlimit[4];
    bool m_llimit[4];
    bool m_home[4];

    uint32_t m_io_in = 0;
    uint32_t m_io_out = 0;
private slots:
    void on_TCPConnected();
    void on_TCPConnectTimeout();
    void on_disconnected();
    void on_timeout();
};

#endif // DMC_B140_M_H
